package org.iamd.security;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.security.auth.Subject;

/**
 * VO моделиращ логнат в системата потребител.
 * 
 * @author И. Атанасов
 */
public class UserContext {

	/**
	 * Map с атрибути отразяващи ресурси свързани с успешно автентикирания
	 * потребител.
	 */
	private Map<String, Object> attributes;

	/** Последно време на активност на потребителя. */
	private long lastAccessedTime;

	/** Автентикиран потребител под формата на {@link Subject}. */
	private Subject subject;

	/** Максимален интервал на неактивност на потребителя. */
	private long timeout;

	/** Уникален идентификатор за логнат потребител. */
	private UUID uniqueId;

	/** Потребител на системата. */
	private IUser user;

	/**
	 * Инициализация на полетата, уникалния идентификатор се генерира.
	 * 
	 * 
	 * @param user
	 *            глобален потребител
	 * @param subject
	 *            автентикиран потребител
	 * @param timeout
	 *            timeout в секунди, ако е -1 контекста е винаги валиден
	 */
	public UserContext(IUser user, Subject subject, int timeout) {
		this.user = user;
		this.subject = subject;
		this.timeout = timeout * 1000;
		this.uniqueId = UUID.randomUUID();
		this.attributes = new HashMap<String, Object>();
		updateActivity();
	}

	/**
	 * По подаден ключ и клас връща стойност на cast-нат атрибут. Хвърля
	 * {@link NullPointerException} ако подадения клас е <code>null</code>.
	 * 
	 * @param key
	 *            име на атрибут
	 * @param clazz
	 *            клас с чиито тип се cast-ва
	 * @param <T>
	 *            тип за cast
	 * 
	 * @return cast-натата стойност на атрибута или <code>null</code> ако няма
	 *         такъв
	 */
	public <T> T getAttribute(String key, Class<T> clazz) {
		return clazz.cast(this.attributes.get(key));
	}

	/**
	 * @return автентикиран потребител
	 */
	public Subject getSubject() {
		return this.subject;
	}

	/**
	 * @return уникален идентификатор
	 */
	public UUID getUniqueId() {
		return this.uniqueId;
	}

	/**
	 * @return потребител
	 */
	public IUser getUser() {
		return this.user;
	}

	/**
	 * Нулира последното време на достъп, така че isStale методът да върне
	 * <code>true</code>.
	 */
	public void invalidate() {
		this.lastAccessedTime = 0;
	}

	/**
	 * @return <code>true</code> ако разликата на текущото време и времето на
	 *         последен достъп е по-голяма от максималния интервал на
	 *         неактивност.
	 */
	public boolean isStale() {
		return this.timeout != -1 ? System.currentTimeMillis() - this.lastAccessedTime > this.timeout
				: false;
	}

	/**
	 * Set-ва стойност за подадения ключ. Ако стойността е <code>null</code>,
	 * премахва стойността за дадения ключ.
	 * 
	 * @param key
	 *            ключ
	 * @param value
	 *            стойност
	 */
	public void setAttribute(String key, Object value) {
		if (value != null) {
			this.attributes.put(key, value);
		} else {
			this.attributes.remove(key);
		}
	}

	/**
	 * Обновява последното време на достъп с текущото време.
	 */
	public void updateActivity() {
		this.lastAccessedTime = System.currentTimeMillis();
	}

}